let a: 10;
let b: "male" | "female"; // 联合类型

a = 10;
// a = 11;// error

b = "female";
// b = "hi";// error

let c: boolean | string;
c = false;
c = "hi";

// 设置为 any 后相当于对该变量关闭了 TS 的类型检测，不建议使用
// let d: any;
let d; // 隐式的any（解析器自动判断）
d = 10;
d = "hi";
d = true;

let e: unknown;
e = 10;
e = "hi";
e = true;

let s: string;
// d 的类型是 any，它可以赋值给任意变量
s = d;
e = "hi";
// e 的类型是 unknown，即使赋值为 string，也不能直接赋值给其他变量
// s = e;// error
if (typeof e === "string") {
  s = e;
}

// 类型断言，可以告诉解析器变量的实际类型
/**
 * 语法：
 * 1. 变量 as 类型；
 * 2. <类型>变量。
 */
s = e as string;
s = <string>e;

function fn(): boolean | string {
  return true;
  // return 1; // error
}

function fn2(num: number) {
  if (num > 0) {
    return true;
  } else {
    return 1;
  }
}

// void 表示空，以函数为例，就表示没有返回值的函数
function fn3(): void {
  return;
  // return undefined;
  // return null; // error
}

// never 表示永远不会返回结果
function fn4(): never {
  throw new Error("xxx");
  // return; // error
}

let f: object;
f = {};
f = function () {};

// 用来指定对象中可以包含哪些属性
// 语法：{ 属性名: 属性值类型 }
let g: { name: string; age?: number }; // age 是可选的属性
// g = {};// error
g = { name: "jerry" };

// [prop: string]: any 表示任意类型的属性
let h: { name: string; [prop: string]: any };
h = { name: "jerry", a: 1, b: true };

// 设置函数结构的类型声明
// 语法：(形参: 类型, 形参: 类型) => 返回值类型
let i: (a: number, b: number) => number;
i = function (a, b) {
  return a + b;
};

/**
 * 数组类型声明语法：
 * 1. 类型[]；
 * 2. Array<类型>。
 */
// string[] 表示字符串数组
let j: string[];
j = ["1", "@"];
// j = [1, "@"];// error

let k: Array<number>;
k = [1, 2];

/**
 * 元组：固定长度的数组 tuple
 */
let l: [string, number];
l = ["hi", 123];

/**
 * enum 枚举
 */
enum Gender {
  Male = 0,
  Female = 1,
}
let m: { name: string; gender: Gender };
m = {
  name: "jerry",
  gender: Gender.Male,
};

console.log(m.gender === Gender.Male); // true

// & 同时成立
let n: { name: string } & { age: number };
n = { name: "jerry", age: 18 };

// 类型的别名
type myType = 1 | 2 | 3 | 4 | 5;
let o: myType;
let p: myType;
o = 1;
// o = 6; // error
